#!/usr/bin/python 

import os
import re
import sys
import logging 

class Branch:
    def __init__(self, mother_node, case=[], pointer=[]):
        self.mother_node = mother_node
        self.case = case 
        self.pointer = pointer

class NodeFor:
    def __init__(self, expression='', source_branch=None, embed=0 ):
        self.expression = expression
        self.source_branch = source_branch
        self.embed = embed
        self.branch = Branch(self)

class NodeIf:
    def __init__(self, expression='', source_branch=None, embed=0 ):
        self.expression = expression
        self.source_branch = source_branch
        self.true_branch = Branch(self)
        self.false_branch = None
        self.embed = embed

class NodeCase:
    def __init__(self, keyword, expression='', source_branch=None, branch={}, embed=0):
        self.keyword = keyword
        self.expression = expression
        self.source_branch = source_branch
        self.branch = branch
        self.embed = embed

class Assignment:
    def __init__(self, trigger_list='', lhs='', rhs='', source_branch=None):
        self.trigger_list = trigger_list
        self.lhs = lhs
        self.rhs = rhs
        self.source_branch = source_branch

class Variable:
    def __init__(self, name='', assignments=[], mother_module=None, reg=False, wire=False, input=False, output=False, inout=False, signed=False, width=(0,0)):
        self.name = name
        self.reg=reg
        self.wire=wire
        self.signed=signed
        self.inout=inout
        self.input=input
        self.output=output
        self.width=width
        self.assignments = assignments[:] 
        self.driver = []
        self.load = []
        self.mother_module = mother_module
        self.index = -1
    def __repr__(self):
        return '\n'+self.name 

    def showme(self, log):
        log.debug(self.name) 
        for i in self.assignments:
            log.debug( '\t\t'+ i.trigger_list+ i.lhs+ '<<=='+ i.rhs)
            paths = []
            branch = i.source_branch
            while branch:
                if isinstance(branch.mother_node, NodeIf):
                    log.debug( '\t\t\t'+ branch.mother_node.expression   )
                    if branch.mother_node.true_branch is branch:
                        log.debug( '\t\t\t\tyes')
                    else:
                        log.debug( '\t\t\t\tno')
                elif isinstance(branch.mother_node, NodeCase):
                    log.debug( '\t\t\t'+ branch.mother_node.expression)
                    for j in branch.mother_node.branch.values():
                        if j is branch:
                            log.debug( '\t\t\t\t'+str(branch.case))
                            break
                #for loop
                elif isinstance(branch.mother_node, NodeFor):
                    log.debug('\t\t\t'+branch.mother_node.expression)
                branch = branch.mother_node.source_branch

class Module:
    def __init__(self):
        self.name=''
        self.variables = []
        self.ports = {}
        self.functions = []
    def get_var_by_name(self,name):
        for i in self.variables:
            if name==i.name:
                #print('got old var %s'%i.name)
                return i
        else:
            var = Variable(name=name, mother_module=self)
            self.variables.append(var)
            #print('got new var %s'%var.name)
            return var
    def __repr__(self):
        return self.name


class File: 
    def __init__(self, name='', daughters=[], text=''):
        self.name = name
        self.daughters = daughters[:]
        self.text = text

class Daughterfile:
    def __init__(self, name='', mother_file=None, offset_in_mother=0, text=''):
        self.name = name
        self.mother = mother_file
        self.offset = offset_in_mother
        self.text = text
        self.length = len(text)
        self.pair = (offset_in_mother, offset_in_mother+self.length)

class Nullobj:
    def __getattr__(self, name):
        return self
    def __call__(self, *args, **kwargs):
        return self

class T:
    def __init__(self, match_string,  next_state, what_on_stack='', paired=False, instance=None, do=Nullobj):
        self.match_string = match_string
        self.next = next_state
        self.stack = what_on_stack
        self.paired = paired
        self.instance = instance
        self.do = do

 
class Parser:
    def __init__(self, log=Nullobj()):
        self.obj = None
        self.port_index = 0
        self.match_string = ''
        self.casenode = None
        self.cases = []
        self.last_if_node = None
        self.state = 'ST_0'
        self.branch = None
        self.trigger_list = ''
        self.keyword_stack = []
        self.embed_stack = []
        self.logic_stack = None
        self.var_name = ''
        self.states = {
            'ST_0' : [T(re.compile('module\s+(\w+)\s*\('),                                        'ST_3', do=self.on_module )],
            'ST_3' : [T(re.compile('(inout|input)\s*((wire)\s+)*(signed\s+)*(\[(.*?):(.*?)\])*'), 'ST_4', do=self.on_port_def_keyword ),
                      T(re.compile('(output)\s*((wire|reg)\s+)*(signed\s+)*(\[(.*?):(.*?)\])*'),  'ST_4', do=self.on_port_def_keyword), 
                      T(re.compile('\w+'),                                                        'ST_5', do=self.on_port_dec)],
            'ST_4' : [T(re.compile('\w+'),                                                        'ST_5', do=self.on_port_def_var)],
            'ST_5' : [T(re.compile(','),                                                          'ST_3' ),
                      T(re.compile('\);'),                                                        'ST_8' )],
            'ST_8':  [T(re.compile('@'),                                                          'ST_23', do=self.on_at),
                      T(re.compile('case[zx]*(?!\w)'),                                            'ST_19', do=self.on_case),
                      T(re.compile('if(?!\w)'),                                                   'ST_21', do=self.on_if),
                      T(re.compile('else\s+if(?!\w)'),                                            'ST_47', do=self.on_elseif),
                      T(re.compile('else(?!\w)'),                                                 'ST_8',  do=self.on_else),
                      T(re.compile('for(?!\w)'),                                                  'ST_22' ),
                      T(re.compile('endcase\s+'),                                                 'ST_8',  do=self.on_endcase ),
                      T(re.compile('begin(\s*:\s*\w+)*(?!\w)'),                                   'ST_8', do=self.on_begin),
                      T(re.compile('always(?!\w)'),                                               'ST_8' ),
                      T(re.compile('endmodule(?!\w)'),                                            'ST_0', do=self.on_endmodule ),
                      T(re.compile('initial(?!\w)'),                                              'ST_8' ),
                      T(re.compile('assign\s+(\w+(\[[^\]]+])*)'),                                 'ST_29', do=self.on_assign),
                      T(re.compile('generate(?!\w)'),                                             'ST_8' ),
                      T(re.compile('endgenerate(?!\w)'),                                          'ST_8' ),
                      T(re.compile('genvar(?!\w)'),                                               'ST_26'),
                      T(re.compile('(integer|real)(?!\w)'),                                       'ST_26'),
                      T(re.compile('()((wire|reg)\s*)(signed)*\s*(\[(.*?):(.*?)\])*'),            'ST_26', do=self.on_port_def_keyword),
                      T(re.compile('(inout|input)\s*((wire)\s+)*(signed\s+)*(\[(.*?):(.*?)\])*'), 'ST_25', do=self.on_port_def_keyword),
                      T(re.compile('(output)\s*((wire|reg)\s+)*(signed\s+)*(\[(.*?):(.*?)\])*'),  'ST_25', do=self.on_port_def_keyword),
                      #T(re.compile('function(\s+signed)*\s*(\[.*?:.*?\])*\s*\w+\s*;'),            'ST_8'),
                      T(re.compile('function\s+.*?\s+endfunction', re.DOTALL),                    'ST_8',  do=self.on_function),
                      T(re.compile('parameter\s*(signed\s+)*(\[.*?:.*?\])*'),                     'ST_27'),
                      #T(re.compile('endfunction(?!\w)'),                                          'ST_8' ),
                      T(re.compile('end(?!\w)'),                                                  'ST_8',  do=self.on_end ),
                      T(re.compile('\$.*?;'),                                                     'ST_8',  do=self.on_task ),
                      T(re.compile('([^\[;=]+?):'),                                                'ST_8',  do=self.on_case_branch ),
                      T(re.compile('([^\.\[;=]+?),'),                                              'ST_20', do=self.on_case_branch_join),
                      T(re.compile('((?!(default|always|begin|if|case|else|generate))(\w+)\s*(?!(always|begin|case|default))[^;<=]*)\s*[<]*=\s*([^;]+);'),
                                                                                                  'ST_8' , do=self.on_assignment),
                      T(re.compile('\w+'),                                                        'ST_30')],
            'ST_26': [T(re.compile('\w+\s*(\[.*?:.*?\])*'),                                       'ST_37', do=self.on_port_def_var)],
            'ST_37': [T(re.compile(','),                                                          'ST_26'),
                      T(re.compile(';'),                                                          'ST_8' ),
                      T(re.compile('=.*?;', re.DOTALL),                                           'ST_8' ),
                      T(re.compile('=.*?,', re.DOTALL),                                           'ST_26')],
            'ST_25': [T(re.compile('\w+'),                                                        'ST_28', do=self.on_port_def_var)],
            'ST_28': [T(re.compile(','),                                                          'ST_25'),
                      T(re.compile(';'),                                                          'ST_8' )],
            'ST_27': [T(re.compile('\w+'),                                                        'ST_29', do=self.on_assign_var)],
            'ST_29': [
                     #T(re.compile('=([^;]+?),', re.DOTALL),                                      'ST_27', do=self.on_assign_val),
                      T(re.compile('=(.*?);', re.DOTALL),                                         'ST_8',  do=self.on_assign_val )],
            'ST_30': [T(re.compile('#\s*\(.*?\)', re.DOTALL),                                     'ST_30', paired=True),
                      T(re.compile('\w+'),                                                        'ST_31')],
            'ST_31': [T(re.compile('\('),                                                         'ST_32')],
            'ST_32': [T(re.compile('\w+'),                                                        'ST_33'),
                      T(re.compile('\.'),                                                         'ST_34')],
            'ST_33': [T(re.compile(','),                                                          'ST_32'),
                      T(re.compile('\)\s*;'),                                                     'ST_8' )],
            'ST_34': [T(re.compile('\w+'),                                                        'ST_35')],
            'ST_35': [T(re.compile('\(.*?\)', re.DOTALL),                                         'ST_36', paired=True)],
            'ST_36': [T(re.compile(','),                                                          'ST_32'),
                      T(re.compile('\)\s*;'),                                                     'ST_8' )],
            'ST_19': [T(re.compile('\(.*?\)', re.DOTALL),                                         'ST_20', paired=True, do=self.on_case_var)], 
            'ST_20': [T(re.compile('(.*?):', re.DOTALL),                                          'ST_8' , do=self.on_case_branch),
                      T(re.compile('(.*?),', re.DOTALL),                                          'ST_20', do=self.on_case_branch_join)],
            'ST_21': [T(re.compile('\(.*?\)', re.DOTALL),                                         'ST_8', paired=True, do=self.on_if_expr )],
            'ST_47': [T(re.compile('\(.*?\)', re.DOTALL),                                         'ST_8', paired=True, do=self.on_elseif_expr )],
            'ST_22': [T(re.compile('\(.*?;.*?;.*?\)', re.DOTALL),                                 'ST_8', paired=True, do=self.on_for )],
            'ST_23': [                                                              
                      T(re.compile('\*'),                                                         'ST_8', do=self.on_trigger ),
                      T(re.compile('\(\*\)'),                                                     'ST_8', do=self.on_trigger ),
                      T(re.compile('\w+'),                                                        'ST_8', do=self.on_trigger ),
                      T(re.compile('\(.*?\)', re.DOTALL),                                         'ST_8', do=self.on_trigger )],
            'ST_38': [T(re.compile(';'),                                                          'ST_8' ),
                      T(re.compile('\('),                                                         'ST_3' )],
            'ST_41': [T(re.compile('\w+\s*=[^,;]+'),                                              'ST_42')],
            'ST_42': [T(re.compile(','),                                                          'ST_41'),
                      T(re.compile(';'),                                                          'ST_8')]
            
        }
        self.log = log
        self.modules = []
        self.file = File()
        self.single_line_comment = re.compile(r"//(.*)$", re.MULTILINE)
        self.multi_line_comment = re.compile(r"/\*(.*?)\*/",re.DOTALL|re.MULTILINE)
        self.include_file = re.compile(r'`include\s+"(.*?)"')
        self.quoted_string = re.compile(r'".*?"', re.DOTALL|re.MULTILINE)
        self.task_instance = re.compile(r'\$.*?;', re.DOTALL)
        #verilog_code = open(in_file_name).read()
        #self.file.text = verilog_code
        #code, macro_list  = self.workout_macro(verilog_code, defined_word, include_dir)
        #self.feed(code)

    def on_module(self):
        one_module = Module()
        one_module.name = self.obj.group(1)
        self.modules.append(one_module)
        self.log.debug('found module %s', one_module.name)
        self.port_index = 0

    def on_port_dec(self):
        var = self.modules[-1].get_var_by_name(self.obj.group())
        var.index = self.port_index
        self.port_index += 1
        self.modules[-1].ports.setdefault(var.name, var) 

    def on_port_def_keyword(self):
        self.last_obj = self.obj

    def on_port_def_var(self):
        var = self.modules[-1].get_var_by_name(self.obj.group())
        direction = self.last_obj.group(1) 
        if direction=='inout': var.inout = True
        elif direction=='input': var.input = True
        elif direction=='output': var.output = True
        kind = self.last_obj.group(3)
        if kind=='reg': var.reg = True
        elif kind=='wire': var.wire = True
        signed = self.last_obj.group(4)
        if signed=='signed': var.signed=True
        self.log.log(8, 'group 1 is %s, 2 is %s, 3 is %s, 4 is %s, 5 is %s, 6 is %s, 7 is %s'%( self.last_obj.group(1), self.last_obj.group(2), self.last_obj.group(3), self.last_obj.group(4), self.last_obj.group(5), self.last_obj.group(6), self.last_obj.group(7)))
        if self.last_obj.group(5):
            var.width = (self.last_obj.group(6), self.last_obj.group(7))
        self.log.log(9, 'got var %s, %r, %r, %r, %r, %r, %r, %r'%(var.name, var.inout, var.input, var.output, var.wire, var.reg, var.signed, var.width))
       
    def on_at(self):
        self.branch = None
        self.trigger_list = ''

    def on_trigger(self):
        self.trigger_list = self.obj.group()

    def on_end_if(self):
        if len(self.embed_stack)>0:
            while self.branch and self.branch.mother_node.embed > len(self.embed_stack):
                self.log.debug('self.embed %d, branch embed %d, %s'%(len(self.embed_stack), self.branch.mother_node.embed, self.branch.mother_node.expression))
                self.branch = self.branch.mother_node.source_branch
                self.log.debug('self.branch is %r'%self.branch)
                if not self.branch:break
        

    def on_task(self):
        if self.embed_stack and (self.embed_stack[-1]=='if' or self.embed_stack[-1]=='for'):
            self.embed_stack.pop()
            self.on_end_if()
        
    def on_assignment(self):
        #1 is left hand side, [] included; 3 is variable; 5 is right hand side
        self.log.log(8, 'group 1 is %s, 2 is %s, 3 is %s, 4 is %s, 5 is %s'%( self.obj.group(1), self.obj.group(2), self.obj.group(3), self.obj.group(4), self.obj.group(5)))
        var = self.modules[-1].get_var_by_name(self.obj.group(3))
        assignment = Assignment(trigger_list=self.trigger_list, lhs=self.obj.group(1), rhs=self.obj.group(5), source_branch=self.branch)
        var.assignments.append(assignment)
        self.log.log(8, 'var %s is assigned %s=%s, with trigger %s, branch%r'%(var.name, assignment.lhs, assignment.rhs, assignment.trigger_list, self.branch))
        if self.embed_stack and self.embed_stack[-1]=='if':
            self.embed_stack.pop()
            self.on_end_if()
        if self.embed_stack and self.embed_stack[-1]=='for':
            self.embed_stack.pop()
        
    def on_if(self):
        pass

    def on_elseif(self):
        self.on_else()

    def on_else(self):
        '''
            IF () BEGIN
            END
                #upon following else, the self.branch is uppper branch, self.last_if_node is the IF() node, the two is NOT the same. That is why we need self.last_if here
            ELSE
        '''
        
        while self.last_if_node and self.last_if_node.embed > (len(self.embed_stack)+1):
            self.log.debug('popping last_if')
            self.last_if_node = self.last_if_node.source_branch.mother_node
        
        branch = Branch(self.last_if_node) 
        self.last_if_node.false_branch =  branch      
        self.branch = branch
        
    def on_case(self):
        if self.embed_stack and self.embed_stack[-1]=='if':
            self.embed_stack[-1]=self.match_string
        else:
            self.embed_stack.append(self.match_string)
        self.log.debug('%r'%self.embed_stack)
        node = NodeCase(self.match_string, source_branch=self.branch, embed=len(self.embed_stack))
        self.casenode = node

    def on_case_var(self):
        self.casenode.expression = self.match_string

    def on_case_branch_join(self):
        self.cases.append(self.obj.group(1)) 

    #FIXME on first case branch, link self.branch with current node, following case branches dont
    def on_case_branch(self):
        self.cases.append(self.obj.group(1))
        branch = Branch(self.casenode) 
        for i in self.cases:
            self.casenode.branch[i] = branch
        if self.branch:
            self.branch.pointer.append(self.casenode)
        self.branch = branch
        self.branch.case = self.cases
        self.cases = []

    def on_for(self):
        self.embed_stack.append('for')
        node = NodeFor(expression=self.match_string, source_branch=self.branch, embed=len(self.embed_stack))
        if self.branch:
            self.branch.pointer.append(node)
        self.branch = node.branch
        

    def on_if_expr(self):
        self.embed_stack.append('if')
        node = NodeIf(expression=self.match_string, source_branch=self.branch, embed=len(self.embed_stack))
        if self.branch:
            self.branch.pointer.append(node)
        self.branch = node.true_branch
        self.last_if_node = node

    def on_elseif_expr(self):
        self.on_if_expr()

    def on_begin(self):
        if self.embed_stack and (self.embed_stack[-1]=='if' or self.embed_stack[-1]=='for'):
            self.embed_stack[-1]=self.match_string
        else:
            self.embed_stack.append(self.match_string)
        self.log.debug('%r'%self.embed_stack)

    def on_end(self):
        self.log.debug('%r'%self.embed_stack)
        self.embed_stack.pop()
        self.on_end_if()

    def on_endcase(self):
        self.on_end()

    def on_assign(self):
        self.var_name = self.obj.group(1)

    def on_assign_var(self):
        self.var_name = self.match_string

    def on_assign_val(self):
        
        #
        # assignment may be separated by comma, need to find out commas not inside curly, to exract assignments
        #
        left_curly  = [i for i in range(len(self.match_string)) if self.match_string[i]=='{']
        right_curly = [i for i in range(len(self.match_string)) if self.match_string[i]=='}']
        commas = [i for i in range(len(self.match_string)) if self.match_string[i]==',']
        if left_curly==right_curly:
            pairs = zip(left_curly, right_curly)
            for pair in pairs:
                for comma in commas[:]:
                    if comma in pair:
                        commas.remove(comma) 
            self.log.log(8, 'I found commas at %r'%commas)

            if commas:
                commas.append(len(self.match_string))
                index = 0
                for i in commas:
                    line = self.match_string[index:i]
                    equal = line.find('=')
                    if index==0:
                        lhs = self.var_name
                    else:
                        lhs = line[:equal].strip()
                    rhs = line[equal+1:]
                    self.log.debug('line is %s, lhs %s, rhs %s'%(line, lhs, rhs))
                    var = self.modules[-1].get_var_by_name(lhs)
                    assignment = Assignment(trigger_list='', lhs=lhs, rhs=rhs, source_branch=None)
                    var.assignments.append(assignment) 
                    index = i+1
            else:
                var = self.modules[-1].get_var_by_name(self.var_name)
                assignment = Assignment(trigger_list='', lhs=self.var_name, rhs=self.obj.group(1), source_branch=None)
                var.assignments.append(assignment) 

            #self.log.debug('%r'%lines)
        else:
            self.log.error('not paired parenthesis in assignment %s'%self.match_string)
            

    def on_function(sefl):
        self.modules[-1].functions.append(self.match_string)
        
    def on_endmodule(self):
        pass
        #for var in self.modules[-1].variables:
        #    var.showme(self.log)

    def match_paired_parenthesis(self, text):
        index = 0
        found = False
        pair = 0
        while not found:
            self.log.log(8, 'index is %d, char is %s, pair is %d'%( index, text, pair) )
            if text[index]==')':
                pair -= 1
                if pair==0:
                    found = True
            elif text[index]=='(':
                pair += 1
            index += 1
        return text[:index] 

    def fun_replace_with_white_space(self, match_obj):
        if(match_obj):
            return re.sub(r"[^\n]", ' ', match_obj.group(0))
    
    def fun_reduce_space_include(self, match_obj):
        if(match_obj):
            return "`include '"+match_obj.group(1)+"'"
            


    def get_content(self, dir_list, file_name):
        for i in dir_list:
            file = os.path.join(i, file_name)
            if os.path.isfile(file):
                return open(file).read()
        else:
            self.log.error('included file %s cannot be opened'%file)
            return '' 

    # FIXME
    # TODO to support nested `ifdef, macro stack is needed
    def workout_macro(self, verilog_code, defined_word=[], include_dir=['.']):
        verilog_code = self.single_line_comment.sub(self.fun_replace_with_white_space, verilog_code)
        verilog_code = self.multi_line_comment.sub(self.fun_replace_with_white_space, verilog_code)
        verilog_code = self.include_file.sub(self. fun_reduce_space_include, verilog_code)
        verilog_code = self.quoted_string.sub(self.fun_replace_with_white_space, verilog_code)
        #verilog_code = self.task_instance.sub(self.fun_replace_with_white_space, verilog_code)
        #print "Here is code"
        #print verilog_code
        #print "Here is end of code"
        start_index = 0
        macro_list = []
        dict_macro = {}
        while(True):
            current_index = verilog_code.find(r'`', start_index)
            if current_index > 0:
                space_location = verilog_code.find(' ', current_index)
                tab_location = verilog_code.find('\t', current_index)
                newline_location = verilog_code.find('\n', current_index) 
                match_obj = re.search(r'`\w+',verilog_code[current_index:])
                macro_keyword = match_obj.group(0) 
                start_index = current_index + 1
                if macro_keyword=='`include':
                    match_obj = re.search(r"\w+\s+'\s*(.+?)\s*'", verilog_code[current_index:])
                    included_file = match_obj.group(1)
                    length = match_obj.end()-match_obj.start()
                    content = self.get_content(include_dir, included_file)
                    verilog_code = "".join([verilog_code[:current_index], ' '*(length+1), content, verilog_code[current_index+length+1:]])
                    verilog_code = self.single_line_comment.sub(self.fun_replace_with_white_space, verilog_code)
                    verilog_code = self.multi_line_comment.sub(self.fun_replace_with_white_space, verilog_code)
                    one_daughter = Daughterfile()
                    one_daughter.name = included_file
                    one_daughter.mother_file = self.file
                    one_daughter.offset = current_index
                    one_daughter.text = content
                    one_daughter.length = len(content)
                    one_daughter.pair = (current_index, current_index+one_daughter.length)
                    self.file.daughters.append(one_daughter)

                elif macro_keyword=='`timescale':
                    verilog_code = ''.join([verilog_code[:current_index], ' '*(newline_location-current_index), verilog_code[newline_location:] ])    #replace `timescale with space
                elif macro_keyword=='`undefine':
                    macro_word = match_obj.group(1)
                    if macro_word in macro_list:
                        macro_list.remove(macro_word)
                        self.log.info('Undefinning macro %s'% macro_word)
                    verilog_code = ''.join([verilog_code[:current_index], ' '*(newline_location-current_index), verilog_code[newline_location:] ])    #replace `undefine with space
                elif macro_keyword=='`define':
                    match_obj = re.search(r'\w+\s+(\w+)(.*?)\n', verilog_code[current_index:]) 
                    macro_word = match_obj.group(1)
                    if macro_word not in macro_list:
                        defined_word.append(macro_word)
                        self.log.info('Definning new macro %s'% macro_word)
                    dict_macro[match_obj.group(1)]=match_obj.group(2) 
                    verilog_code = ''.join([verilog_code[:current_index], ' '*(newline_location-current_index), verilog_code[newline_location:] ])    #replace `define with space
                elif macro_keyword=='`ifdef':
                    match_obj = re.search(r'\w+\s+(\w+)', verilog_code[current_index:])
                    macro_word = match_obj.group(1)
                    self.log.info('ifdef macro %s'% macro_word)
                    if macro_word not in macro_list:
                        macro_list.append(macro_word)
                    if macro_word in defined_word:
                        defined = True
                    else:
                        defined = False
                    macro_block_start_index = current_index
                    verilog_code = ''.join([verilog_code[:current_index], ' '*(newline_location-current_index), verilog_code[newline_location:] ])    #replace `ifdef with space
                elif macro_keyword=='`ifndef':
                    match_obj = re.search(r'\w+\s+(\w+)', verilog_code[current_index:])
                    macro_word = match_obj.group(1)
                    self.log.info('ifndef macro %s'% macro_word)
                    if macro_word not in macro_list:
                        macro_list.append(macro_word)
                    if macro_word in defined_word:
                        defined = False
                    else:
                        defined = True
                    macro_block_start_index = current_index
                    verilog_code = ''.join([verilog_code[:current_index], ' '*(newline_location-current_index), verilog_code[newline_location:] ])    #replace `ifndef with space
                elif macro_keyword=='`else':
                    macro_block_end_index = current_index
                    lines = verilog_code[macro_block_start_index:macro_block_end_index].count('\n')
                    if defined:
                        verilog_code = ''.join([verilog_code[:current_index], ' '*5, verilog_code[current_index+5:] ])    #replace `else with space
                        defined = False
                        self.log.info('else macro %s'% macro_word)
                    else:
                        verilog_code = ''.join([verilog_code[:macro_block_start_index], ' '*(macro_block_end_index-macro_block_start_index+5-lines), '\n'*lines, verilog_code[macro_block_end_index+5:]])
                        defined = True
                        self.log.info('ifndef macro %s'% macro_word)
                    macro_block_start_index = current_index
                elif macro_keyword=='`endif':
                    macro_block_end_index = current_index
                    lines = verilog_code[macro_block_start_index:macro_block_end_index].count('\n')
                    self.log.info('end of macro %s'% macro_word)
                    if defined:
                        verilog_code = ''.join([verilog_code[:current_index], ' '*5, verilog_code[current_index+6:]]) #replace `endif with space
                        define = False                  #restore to default
                    else:
                        verilog_code = ''.join([verilog_code[:macro_block_start_index], ' '*(macro_block_end_index-macro_block_start_index+6-lines), '\n'*lines, verilog_code[macro_block_end_index+6:] ])
            else:
                break
        #print "Here is code"
        #print verilog_code
        #print "Here is end of code"
        #os._exit(5)
        return verilog_code, macro_list
        
                        

    def feed(self, in_file_name, defined_word, include_dir):
        if os.path.isfile(in_file_name):
            verilog_code = open(in_file_name).read()
        else:
            verilog_code = ''
        text, macro_list  = self.workout_macro(verilog_code, defined_word, include_dir)
        index = 0
        line_no = 1                 # file line number starts with 1
        keyword_stack = []
        condition_stack = []
        if_else_stack = []
        end_address = len(text)
        pop_condition_on_end = 0
        while index < end_address:
            if text[index] in [' ', '\t', '\n', '\r']:
                if text[index]=='\n':
                    line_no += 1
                index += 1
            else:
                for t in self.states[self.state]:
                    self.log.log(8, 'trying %r'%(t.match_string))
                    self.obj = re.match(t.match_string, text[index:])
                    if self.obj:
                        match_string = self.obj.group()
                        if t.paired:
                            match_string = self.match_paired_parenthesis(text[index:])
                        index += len(match_string)
                        self.match_string = match_string
                        self.state = t.next 
                        line_no += match_string.count('\n') 
                        t.do() 
                        self.log.log(10, '\n\n\tnext state is %s, index is %d, line is %d, match is %s '%(t.next, index, line_no, match_string))
                        break 
                #no transition occur
                else:
                    self.log.error('\n\nFailed, unknown syntax\n%s'%text[index:index+100]) 
                    return
                        
################################################################################

date = " 2010-08-18, 16:46:51"
version = 1
message = """
                          Copyright (c) by Xiaokun Guo
                              All rights reserved
                           """+date+', Version '+str(version).zfill(4)+'\n'

if __name__=='__main__':
    mylog = logging.getLogger()
    mylog.setLevel(logging.INFO)
    #mylog.setLevel(8)
    handler = logging.FileHandler( 'log', 'w')
    mylog.addHandler(handler)
    #handler = logging.StreamHandler(sys.stdout)
    #mylog.addHandler(handler)

    defined_word = ['USBF_VERBOSE_DEBUG', 'USBF_ASYNC_RESET', 'USBF_DEBUG', 'USBF_VERBOSE_DEBUG']
    #defined_word = ['DW01_ADD_INCLUDED']
    print message
    if len(sys.argv)<2:
        print 'Need a file to procedd'
        os._exit(1)

    myparser = Parser(log=mylog)
    for file in sys.argv[1:]:
        mylog.debug('working on %s', file)
        myparser.feed(file, defined_word=defined_word, include_dir=['./verilog/'] )
    #myparser = Parser(sys.argv[1], log=mylog, defined_word=defined_word) 
    for module in myparser.modules:
        for var in module.variables:
            var.showme(mylog)
        for func in module.functions:
            self.log.debug(func)
